package org.geekbang.thinking.in.spring.dependency.lookup;

import org.geekbang.thinking.in.spring.ioc.overview.domain.User;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * 类型安全 依赖查找示例
 */
public class TypeSafetyDependencyLookupDemo {

    public static void main(String[] args) {
        //创建 BeanFactory 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        //注册 Configuration Class (配置类)
        applicationContext.register(TypeSafetyDependencyLookupDemo.class);

        //启动 Spring 应用上下文(XML配置方式不需要)
        applicationContext.refresh();

        //演示 BeanFactory#getBean 方法的安全情况
        displayBeanFactoryGetBean(applicationContext);
        //演示 ObjectFactory#getObject 方法的安全情况
        displayObjectFactoryGetObject(applicationContext);
        //演示 ObjectProvider#getIfAvaiable 方法的安全性
        displayObjectProviderIfAvaliable(applicationContext);
        //演示 ListableBeanFactory#getBeansOfType 方法的安全性
        displayListableBeanFactoryGetBeansOfType(applicationContext);
        //演示ObjectProvider#stream 方法的安全性
        displayObjectProviderStreamOps(applicationContext);
        //演示displayApplicationContextGetBean
        displayApplicationContextGetBean(applicationContext);
        //显式的关闭 Spring 应用上下文
        applicationContext.close();
    }

    private static void displayObjectProviderStreamOps(AnnotationConfigApplicationContext applicationContext) {
        ObjectProvider<User> userObjectProvider= applicationContext.getBeanProvider(User.class);
        printBeansException("displayObjectProviderStreamOps",()->userObjectProvider.forEach(System.out::println));
    }

    private static void displayListableBeanFactoryGetBeansOfType(AnnotationConfigApplicationContext applicationContext) {
        ListableBeanFactory beanFactory = applicationContext;
        printBeansException("displayListableBeanFactoryGetBeansOfType",()->beanFactory.getBeansOfType(User.class));

    }

    private static void displayObjectProviderIfAvaliable(AnnotationConfigApplicationContext applicationContext) {
        ObjectProvider<User> userObjectProvider= applicationContext.getBeanProvider(User.class);
        printBeansException("displayObjectProviderIfAvaliable",()->userObjectProvider.getIfAvailable());
    }

    private static void displayObjectFactoryGetObject(AnnotationConfigApplicationContext applicationContext) {
        //ObjectProvider is ObjectFactory
        ObjectFactory<User> userObjectFactory = applicationContext.getBeanProvider(User.class);
        printBeansException("displayObjectFactoryGetObject",()->userObjectFactory.getObject());
    }

    private static void displayBeanFactoryGetBean(BeanFactory beanFactory){
        printBeansException("displayBeanFactoryGetBean", () ->beanFactory.getBean(User.class));
    }

    private static void displayApplicationContextGetBean(AnnotationConfigApplicationContext applicationContext){
        printBeansException("displayApplicationContextGetBean", () ->applicationContext.getBean(User.class));
    }

    private static void printBeansException(String source,Runnable runnable){
        System.err.println("Source from : "+source);
        try{
            runnable.run();
        }catch (BeansException exception){
            exception.printStackTrace();
        }
    }
}
